/*
 * Class based on CKS.SPTagCloud
 * with new methods to get tags
 * and modification in the render
 */

using System;
using System.Data;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.Xml.Serialization;
using System.Web.UI.HtmlControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Publishing;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebControls;
using System.Collections;
using System.Globalization;
using BDF.TagCloud.Utilities;

namespace BDF.TagCloud
{
    [DefaultProperty("Text")]
    [ToolboxData("<{0}:TagCloud runat=server></{0}:TagCloud>")]
    [Microsoft.SharePoint.Security.SharePointPermission(System.Security.Permissions.SecurityAction.LinkDemand, ObjectModel = true)]
    [System.Web.AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = System.Web.AspNetHostingPermissionLevel.Minimal)]
    [XmlRoot(Namespace = "BDF.TagCloud")]
    public class TagCloud : WebPart
    {
        private int maxCount = 1;
        private bool useCss = false;
        private string tagCssPrefix = String.Empty;
        private string tagColumnName = "Tags";
        private string tagPageURL; //if null, it's current page which is used
        private char delimiter = ';';        

        private string[] fontSizes = new string[] { "22", "18", "14", "12", "10", "9" };

        [Bindable(true)]
        [LocalizedCategoryAttribute("TaggingCategory")]
        [LocalizedWebDisplayNameAttribute("TagColumnTitle")]
        [DefaultValue("")]
        [Localizable(true)]
        public string TagColumnName
        {
            get
            {
                return ((this.tagColumnName == null) ? String.Empty : this.tagColumnName);
            }

            set
            {
                this.tagColumnName = value;
            }
        }

        [Bindable(true)]
        [Category("Tagging Setting")]
        [DefaultValue("")]
        [Localizable(true)]
        [LocalizedCategoryAttribute("TaggingCategory")]
        [LocalizedWebDisplayNameAttribute("TagPageURLTitle")]
        [LocalizedWebDescriptionAttribute("TagPageURLDesc")]
        public string TagPageURL
        {
            get
            {
                return ((this.tagPageURL == null) ? String.Empty : this.tagPageURL);
            }

            set
            {
                this.tagPageURL = value;
            }
        }

        [Bindable(true)]
        [LocalizedCategoryAttribute("TaggingCategory")]
        [LocalizedWebDisplayNameAttribute("DelimiterTitle")]
        [DefaultValue(";")]
        [Localizable(true)]
        public char Delimiter
        {
            get
            {
                return this.delimiter;
            }

            set
            {
                this.delimiter = value;
            }
        }

        [Bindable(true)]
        [DefaultValue("")]
        [Localizable(true)]
        [LocalizedCategoryAttribute("TaggingCategory")]
        [LocalizedWebDisplayNameAttribute("CssPrefixTitle")]
        [LocalizedWebDescriptionAttribute("CssPrefixDesc")]
        public string TagCssPrefix
        {
            get
            {
                return ((this.tagCssPrefix == null) ? String.Empty : this.tagCssPrefix);
            }

            set
            {
                this.tagCssPrefix = value;
            }
        }

        [Bindable(true)]
        [DefaultValue(false)]
        [LocalizedCategoryAttribute("TaggingCategory")]
        [LocalizedWebDisplayNameAttribute("UseCssTitle")]
        [LocalizedWebDescriptionAttribute("UseCssDesc")]
        public bool UseCss
        {
            get
            {
                return this.useCss;
            }
            set
            {
                this.useCss = value;
            }
        }

        protected override void RenderWebPart(HtmlTextWriter output)
        {
            //get the current page to the tags link
            if (this.tagPageURL == null || this.tagPageURL==string.Empty)
                this.tagPageURL = Page.Request.Path;

            //Get all tags
            IEnumerable arrayTags = this.GetTags();

            HtmlGenericControl tagCloudDiv = new HtmlGenericControl("div");
            tagCloudDiv.Attributes.Add("id", "tagCloud");
            this.Controls.Add(tagCloudDiv);

            foreach (Tag tag in arrayTags)
            {
                this.HorizontalAlign = HorizontalAlign.Right;

                HtmlAnchor a = new HtmlAnchor();
                a.HRef = tag.Url;
                a.Title = tag.Count.ToString() +" "+ SPUtility.GetLocalizedString("$Resources:TagCount", "TagCloudFeature", SPContext.Current.Web.Language);
                a.InnerText = SPEncode.HtmlEncode(tag.Name);


                int weight = Helper.GetTagWeight(tag.Count, this.maxCount);
                if (weight > 0)
                {
                    if (this.useCss)
                    {
                        a.Attributes["class"] = this.tagCssPrefix + weight.ToString();
                    }
                    else
                    {
                        a.Style.Add(HtmlTextWriterStyle.FontSize, fontSizes[weight - 1]);
                    }
                    tagCloudDiv.Controls.Add(a);

                    // adding some spaces between tags
                    LiteralControl lc = new LiteralControl("  ");
                    tagCloudDiv.Controls.Add(lc);

                }

            }
            tagCloudDiv.RenderControl(output);
            
        }

        //Get Tags requesting site collection (all sites) on lists and doclib
        //Return a SortedDictionnary to optimize the results search
        protected SortedDictionary<string, Tag>.ValueCollection GetTags()
        {
            
            try
            {
                DataTable results = LaunchQuery(1); //request on doclib
                DataTable results2 = LaunchQuery(0); //request on lists

                results.Merge(results2); //merge results of two requests, each row has the Tags value

                //table will contains the tags element
                SortedDictionary<string, Tag> table = new SortedDictionary<string, Tag>();

                foreach (DataRow row in results.Rows)
                {
                    string valueTags = row["Tags"].ToString();
                    //Verify in first if the "Tags" value is empty
                    if (!valueTags.Equals(string.Empty))
                    {
                        //Get all tags of one item 
                        string[] tags = valueTags.Split(this.delimiter);

                        //for each of them either we increse the count or we create a tag object initialised at 1
                        for (int i = 0; i < tags.Length; i++)
                        {
                            string tagName = tags[i];
                            Tag updatedTag;
                            if (table.TryGetValue(tagName, out updatedTag))
                            {
                                updatedTag.Count++;
                            }
                            else
                            {
                                updatedTag = new Tag(tagName, 1,this.tagPageURL +"?tags="+ SPEncode.HtmlEncode(tagName));
                                table.Add(tagName, updatedTag);
                            }
                        }
                    }
                }

                //update of maxcount
                foreach (Tag tag in table.Values)
                {
                    if (tag.Count > maxCount)
                        maxCount = tag.Count;
                }
                return table.Values;
                
            }
            catch (Exception ex)
            {
                return null;
            }
           
        }

        //launch one request on the site collection and all sites, searching lists or doclib which has "Tags" column
        protected DataTable LaunchQuery(int typeListe)
        {
            string lists = "<Lists BaseType=\"" + typeListe + "\" />";
            string viewFields = "<FieldRef Name=\"Tags\" />";
            string webs = "<Webs Scope=\"Recursive\" />"; 
            CrossListQueryInfo query = new CrossListQueryInfo();
            query.RowLimit = 10000;
            query.WebUrl = SPContext.Current.Site.ServerRelativeUrl;
            query.Lists = lists;
            query.Webs = webs;
            query.Query = "<Where><Neq><FieldRef Name=\"Tags\" /><Value Type=\"Text\">" + String.Empty + "</Value></Neq></Where>";
            query.ViewFields = viewFields;
            query.UseCache = true; //use the cache for optimize results

            CrossListQueryCache cache = new CrossListQueryCache(query);

            return cache.GetSiteData(SPContext.Current.Site);
        }
    }


}
